import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';

import { DatasetSearchModeMap } from '@/common/types/dataset';
import useWindowWidth from '@/hooks/event/use-window-width';
import { t } from '@/locales/i18n';
import { ChatHistoryItemResType } from '@/types/chat/type';
import { moduleTemplatesFlat } from '@/types/workflow/template/constants';

import { SvgIcon } from '../icon';
import Markdown from '../markdown';

import { QuoteList } from './QuoteList';

type sideTabItemType = {
  moduleLogo?: string;
  moduleName: string;
  runningTime?: number;
  moduleType: string;
  // nodeId:string; // abandon
  id: string;
  children: sideTabItemType[];
};

/* Per response value */
export const WholeResponseContent = ({
  activeModule,
  hideTabs,
  showDetail,
}: {
  activeModule: ChatHistoryItemResType;
  hideTabs?: boolean;
  showDetail: boolean;
}) => {
  // Auto scroll to top
  const ContentRef = useRef<HTMLDivElement>(null);
  useEffect(() => {
    if (ContentRef.current) {
      ContentRef.current.scrollTop = 0;
    }
  }, [activeModule]);

  const RowRender = useCallback(
    ({
      children,
      label,
      className,
      mb,
    }: {
      children: React.ReactNode;
      label: string;
      className?: string;
      mb?: number;
    }) => {
      return (
        <div className="mb-3 flex flex-col gap-2">
          <div className={`text-xs mb-${mb} font-font-weight-600 text-text-4`}>{label}:</div>
          <div
            className={`${className} boder rounded-md border-line-2 bg-fill-1 p-2 pl-3 text-xs text-text-4`}
          >
            {children}
          </div>
        </div>
      );
    },
    [],
  );
  const Row = useCallback(
    ({
      label,
      value,
      rawDom,
    }: {
      label: string;
      value?: string | number | boolean | object;
      rawDom?: React.ReactNode;
    }) => {
      const val = value || rawDom;
      const isObject = typeof value === 'object';
      const formatValue = isObject ? `~~~json\n${JSON.stringify(value, null, 2)}` : `${value}`;

      if (rawDom) {
        return (
          <RowRender label={label} mb={1}>
            {rawDom}
          </RowRender>
        );
      }

      if (val === undefined || val === '' || val === 'undefined') return null;

      return (
        <RowRender label={label} mb={isObject ? 0 : 1}>
          <Markdown source={formatValue} />
        </RowRender>
      );
    },
    [RowRender],
  );

  return activeModule ? (
    <div className={`h-full px-4 py-2 ${hideTabs ? '' : 'flex-1 overflow-auto'}`} ref={ContentRef}>
      {/* common info */}
      <Row label={t('core.chat.response.module name')} value={t(activeModule.moduleName as any)} />
      <Row
        label={t('core.chat.response.module time')}
        value={`${activeModule?.runningTime || 0}s`}
      />
      {activeModule?.metricsResult !== undefined && (
        <Row
          label={t('core.chat.response.module metrics')}
          value={`${activeModule?.metricsResult}`}
        />
      )}
      <Row label={t('core.chat.response.module model')} value={activeModule?.model} />
      <Row label={t('core.chat.response.module tokens')} value={`${activeModule?.tokens}`} />
      <Row
        label={t('core.chat.response.Tool call tokens')}
        value={`${activeModule?.toolCallTokens}`}
      />

      <Row label={t('core.chat.response.module query')} value={activeModule?.query} />
      <Row
        label={t('core.chat.response.context total length')}
        value={activeModule?.contextTotalLen}
      />
      <Row label={t('response.Error')} value={activeModule?.error} />
      <Row label={t('response.node_inputs')} value={activeModule?.nodeInputs} />
      {/* ai chat */}
      <Row label={t('core.chat.response.module temperature')} value={activeModule?.temperature} />
      <Row label={t('core.chat.response.module maxToken')} value={activeModule?.maxToken} />
      <Row
        label={t('core.chat.response.module historyPreview')}
        rawDom={
          activeModule.historyPreview ? (
            <div className="rounded-md border border-bgBase px-3 py-2">
              {activeModule.historyPreview?.map((item, i) => (
                <div
                  key={i}
                  className={`${
                    i === (activeModule.historyPreview?.length || 0) - 1
                      ? ''
                      : 'mb-2 border-b-2 border-gray-500'
                  } pb-2`}
                >
                  <div className="font-bold">{item.obj}</div>
                  <div className="whitespace-pre-wrap">{item.value}</div>
                </div>
              ))}
            </div>
          ) : (
            ''
          )
        }
      />
      {/* dataset search */}
      {activeModule?.searchMode && (
        <Row
          label={t('core.dataset.search.search mode')}
          // @ts-ignore
          value={t(DatasetSearchModeMap[activeModule.searchMode]?.title)}
        />
      )}
      <Row label={t('core.chat.response.module similarity')} value={activeModule?.similarity} />
      <Row label={t('core.chat.response.module limit')} value={activeModule?.limit} />
      <Row
        label={t('core.chat.response.search using reRank')}
        value={`${activeModule?.searchUsingReRank}`}
      />
      <Row label={t('core.chat.response.Extension model')} value={activeModule?.extensionModel} />
      <Row
        label={t('support.wallet.usage.Extension result')}
        value={`${activeModule?.extensionResult}`}
      />
      <Row label={t('core.workflow.debug.mcp result')} value={activeModule?.toolRes} />
      {activeModule.quoteList && activeModule.quoteList.length > 0 && (
        <Row
          label={t('core.chat.response.module quoteList')}
          rawDom={<QuoteList showDetail={showDetail} rawSearch={activeModule.quoteList} />}
        />
      )}
      {/* classify question */}
      <Row label={t('core.chat.response.module cq result')} value={activeModule?.cqResult} />
      <Row
        label={t('core.chat.response.module cq')}
        value={(() => {
          if (!activeModule?.cqList) return '';
          return activeModule.cqList.map((item) => `* ${item.value}`).join('\n');
        })()}
      />
      {/* if-else */}
      <Row
        label={t('core.chat.response.module if else Result')}
        value={activeModule?.ifElseResult}
      />
      {/* extract */}
      <Row
        label={t('core.chat.response.module extract description')}
        value={activeModule?.extractDescription}
      />
      <Row
        label={t('core.chat.response.module extract result')}
        value={activeModule?.extractResult}
      />
      {/* http */}
      <Row label="Headers" value={activeModule?.headers} />
      <Row label="Params" value={activeModule?.params} />
      <Row label="Body" value={activeModule?.body} />
      <Row label={t('core.chat.response.module http result')} value={activeModule?.httpResult} />
      {/* plugin */}
      <Row label={t('core.chat.response.plugin output')} value={activeModule?.pluginOutput} />
      {/* text output */}
      <Row label={t('core.chat.response.text output')} value={activeModule?.textOutput} />
      {/* code */}
      <Row label={t('response.Custom inputs')} value={activeModule?.customInputs} />
      <Row label={t('response.Custom outputs')} value={activeModule?.customOutputs} />
      <Row label={t('response.Code log')} value={activeModule?.codeLog} />

      {/* read files */}
      {activeModule?.readFiles && activeModule?.readFiles.length > 0 && (
        <Row
          label={t('response.read files')}
          rawDom={
            <div className="flex flex-wrap gap-3 px-4 py-2">
              {activeModule?.readFiles.map((file, i) => (
                <div
                  key={i}
                  className={`rounded-sm bg-white px-2 py-1 shadow-md ${
                    file.url ?? 'cursor-pointer'
                  }`}
                  {...(file.url
                    ? {
                        onClick: () => window.open(file.url),
                      }
                    : {})}
                >
                  <SvgIcon icon={file.name as any} size="1rem" />
                  <span>{file.name}</span>
                </div>
              ))}
            </div>
          }
        />
      )}
      <Row label={t('response.Read file result')} value={activeModule?.readFilesResult} />

      {/* user select */}
      <Row
        label={t('core.chat.response.user_select_result')}
        value={activeModule?.userSelectResult}
      />

      {/* update var */}
      <Row
        label={t('core.chat.response.update_var_result')}
        value={activeModule?.updateVarResult}
      />

      {/* loop */}
      <Row label={t('core.chat.response.loop_input')} value={activeModule?.loopInput} />
      <Row label={t('core.chat.response.loop_output')} value={activeModule?.loopResult} />

      {/* loopStart */}
      <Row
        label={t('core.chat.response.loop_input_element')}
        value={activeModule?.loopInputValue}
      />

      {/* loopEnd */}
      <Row
        label={t('core.chat.response.loop_output_element')}
        value={activeModule?.loopOutputValue}
      />

      {/* form input */}
      <Row label={t('form_input_result')} value={activeModule?.formInputResult} />

      {/* tool params */}
      <Row label={t('tool_params.tool_params_result')} value={activeModule?.toolParamsResult} />
    </div>
  ) : null;
};

/* Side tab: With and without children */
const NormalSideTabItem = React.memo(
  ({
    sideBarItem,
    onChange,
    value,
    index,
    children,
  }: {
    sideBarItem: sideTabItemType;
    onChange: (id: string) => void;
    value: string;
    index: number;
    children?: React.ReactNode;
  }) => {
    const leftIndex = index > 3 ? 3 : index;
    return (
      <div
        className={`flex items-center ${
          value === sideBarItem.id ? 'bg-gray-500' : ''
        } w-full cursor-pointer p-2 hover:bg-gray-100 ${
          leftIndex === 0 ? 'pl-[0.5rem]' : `pl-[${1.5 * leftIndex + 0.5}rem]`
        } relative rounded-md`}
        onClick={() => {
          onChange(sideBarItem.id);
        }}
      >
        <SvgIcon
          icon={
            (sideBarItem.moduleLogo ||
              moduleTemplatesFlat.find(
                (template) => sideBarItem.moduleType === template.flowNodeType,
              )?.avatar)!
          }
          size="1.5rem"
        />
        <div className="ml-2">
          <div className="text-sm font-bold">{t(sideBarItem.moduleName as any)}</div>
          <div className="text-xs text-gray-600">{`${t(sideBarItem.runningTime as any)}s`}</div>
        </div>
        <div className="absolute right-2 top-1/2 h-5 w-5 -translate-y-1/2">{children}</div>
      </div>
    );
  },
);

const AccordionToggleButton = React.memo(
  ({
    index,
    sideBarItem,
    onChange,
    value,
  }: {
    index: number;
    sideBarItem: sideTabItemType;
    onChange: (id: string) => void;
    value: string;
  }) => {
    const [isOpen, setOpen] = useState(false);

    return (
      <>
        <SvgIcon
          size="20px"
          icon={isOpen ? 'core/chat/chevronUp' : 'core/chat/chevronDown'}
          onClick={(e) => {
            e.stopPropagation();
            setOpen(!isOpen);
          }}
          className="cursor-pointer hover:text-primary"
        />
        {isOpen && (
          <div className="relative">
            {sideBarItem.children.map((item) => (
              <SideTabItem
                value={value}
                key={item.id}
                sideBarItem={item}
                onChange={onChange}
                index={index + 1}
              />
            ))}
          </div>
        )}
      </>
    );
  },
);

const SideTabItem = ({
  sideBarItem,
  onChange,
  value,
  index,
}: {
  sideBarItem: sideTabItemType;
  onChange: (id: string) => void;
  value: string;
  index: number;
}) => {
  if (!sideBarItem) return null;

  return sideBarItem.children.length !== 0 ? (
    <div>
      <div className="relative flex items-center">
        <NormalSideTabItem
          index={index}
          value={value}
          onChange={onChange}
          sideBarItem={sideBarItem}
        >
          <AccordionToggleButton
            index={index}
            sideBarItem={sideBarItem}
            onChange={onChange}
            value={value}
          />
        </NormalSideTabItem>
      </div>
    </div>
  ) : (
    <NormalSideTabItem index={index} value={value} onChange={onChange} sideBarItem={sideBarItem} />
  );
};

/* Modal main container */
export const ResponseBox = React.memo(function ResponseBox({
  response,
  showDetail,
  hideTabs = false,
  useMobile = false,
}: {
  response: ChatHistoryItemResType[];
  showDetail: boolean;
  hideTabs?: boolean;
  useMobile?: boolean;
}) {
  const { isPc } = useWindowWidth();

  const flattedResponse = useMemo(() => {
    /* Flat response */
    function flattenArray(arr: ChatHistoryItemResType[]) {
      const result: ChatHistoryItemResType[] = [];

      function helper(currentArray: ChatHistoryItemResType[]) {
        currentArray.forEach((item) => {
          if (item && typeof item === 'object') {
            result.push(item);

            if (Array.isArray(item.toolDetail)) {
              helper(item.toolDetail);
            }
            if (Array.isArray(item.pluginDetail)) {
              helper(item.pluginDetail);
            }
            if (Array.isArray(item.loopDetail)) {
              helper(item.loopDetail);
            }
          }
        });
      }

      helper(arr);
      return result;
    }

    return flattenArray(response).map((item) => ({
      ...item,
      id: item.id ?? item.nodeId,
    }));
  }, [response]);
  const [currentNodeId, setCurrentNodeId] = useState(
    flattedResponse[0]?.id ?? flattedResponse[0]?.nodeId ?? '',
  );

  const activeModule = useMemo(
    () => flattedResponse.find((item) => item.id === currentNodeId) as ChatHistoryItemResType,
    [currentNodeId, flattedResponse],
  );

  const sliderResponseList: sideTabItemType[] = useMemo(() => {
    /* Format response data to slider data */
    function pretreatmentResponse(res: ChatHistoryItemResType[]): sideTabItemType[] {
      return res.map((item) => {
        const children: sideTabItemType[] = [];
        if (item?.toolDetail || item?.pluginDetail || item?.loopDetail) {
          if (item?.toolDetail) children.push(...pretreatmentResponse(item?.toolDetail));
          if (item?.pluginDetail) children.push(...pretreatmentResponse(item?.pluginDetail));
          if (item?.loopDetail) children.push(...pretreatmentResponse(item?.loopDetail));
        }

        return {
          moduleLogo: item.moduleLogo,
          moduleName: item.moduleName,
          runningTime: item.runningTime,
          moduleType: item.moduleType,
          id: item.id ?? item.nodeId,
          children,
        };
      });
    }
    return pretreatmentResponse(response);
  }, [response]);

  // const {
  //   isOpen: isOpenMobileModal,
  //   onOpen: onOpenMobileModal,
  //   onClose: onCloseMobileModal,
  // } = useDisclosure();

  const [isOpenMobileModal, setIsOpenMobileModal] = useState(false);

  const onOpenMobileModal = () => {
    setIsOpenMobileModal(true);
  };

  const onCloseMobileModal = () => {
    setIsOpenMobileModal(false);
  };

  const WholeResponseSideTab = useCallback(
    ({
      response,
      value,
      onChange,
      isMobile = false,
    }: {
      response: sideTabItemType[];
      value: string;
      onChange: (index: string) => void;
      isMobile?: boolean;
    }) => {
      return (
        <>
          {response.map((item) => (
            <div
              key={item.id}
              style={{
                minWidth: '12rem',
              }}
              className={`${isMobile ? 'm-3 bg-gray-100' : ''} rounded-md`}
            >
              <SideTabItem value={value} onChange={onChange} sideBarItem={item} index={0} />
            </div>
          ))}
        </>
      );
    },
    [],
  );

  return (
    <div>
      {isPc && !useMobile ? (
        <div className="flex h-full overflow-hidden">
          <div className="border-r-2 p-3">
            <div className="h-full overflow-auto">
              <WholeResponseSideTab
                response={sliderResponseList}
                value={currentNodeId}
                onChange={setCurrentNodeId}
              />
            </div>
          </div>
          <div className="h-full">
            <WholeResponseContent
              activeModule={activeModule}
              hideTabs={hideTabs}
              showDetail={showDetail}
            />
          </div>
        </div>
      ) : (
        <div className="h-full overflow-auto">
          {!isOpenMobileModal && (
            <WholeResponseSideTab
              response={sliderResponseList}
              value={currentNodeId}
              onChange={(item: string) => {
                setCurrentNodeId(item);
                onOpenMobileModal();
              }}
              isMobile
            />
          )}
          {isOpenMobileModal && (
            <div className="flex h-full flex-col">
              <div className="relative flex h-10 items-center justify-center border-b-2 px-2 py-2">
                <SvgIcon
                  size={4}
                  icon="ic-back"
                  onClick={(e) => {
                    e.stopPropagation();
                    onCloseMobileModal();
                  }}
                  className="t-1/2 absolute left-2 -translate-y-1/2 cursor-pointer hover:text-primary"
                />

                <SvgIcon
                  icon={
                    activeModule.moduleLogo ||
                    moduleTemplatesFlat.find(
                      (template) => activeModule.moduleType === template.flowNodeType,
                    )?.avatar ||
                    'default-icon'
                  }
                  size="1.25rem"
                />

                <div className="ml-2 flex items-center" style={{ lineHeight: '1.25rem' }}>
                  {t(activeModule.moduleName as any)}
                </div>
              </div>
              <div className="flex-1">
                <WholeResponseContent
                  activeModule={activeModule}
                  hideTabs={hideTabs}
                  showDetail={showDetail}
                />
              </div>
            </div>
          )}
        </div>
      )}
    </div>
  );
});
